package org.andao.commons.history;


import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.andao.commons.model.HistoryModel;
import org.andao.core.annotation.Historizable;
import org.andao.core.base.model.Model;
import org.andao.core.dao.listener.OperationType;
import org.andao.core.utils.ExBeanUtils;
import org.andao.core.utils.JsonUtils;
import org.andao.security.SpringSecurityHelper;
import org.andao.security.model.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.event.EventSource;
import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 使用hibernate监听器，用来处理审计日志. <p>
 * 
 * @author Marco.hu(hzg139@163.com)
 */
public class HistoryEvenListener implements PostUpdateEventListener ,PostInsertEventListener,PostDeleteEventListener{
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	private static final long serialVersionUID = 1300859460968614799L;
	

	/*
	 * 更新审计
	 * @see org.hibernate.event.PostUpdateEventListener#onPostUpdate(org.hibernate.event.PostUpdateEvent)
	 */
	public void onPostUpdate(PostUpdateEvent event) {
		Object entity = event.getEntity();
		if(isAableLog(entity,OperationType.UPDATE)){//如果可记录日志则
			 Object[] oldValues = event.getOldState();//旧的属性
			 Object[] newValues = event.getState();//新的属性
		     String[] properties = event.getPersister().getPropertyNames();
			 	 
		     User currentUser = SpringSecurityHelper.getCurrentUser();
		     
		 	 boolean isChanged=false;
		 	 boolean isDeleted = false;
		 	 Map<String, Object> oldDataMap = new HashMap<String, Object>();
		 	 Map<String, Object> newDataMap = new HashMap<String, Object>();
		 	 
		     for(int i=0;i<properties.length;i++){
		    	 if ((oldValues[i] != null && !oldValues[i].equals(newValues[i])) || (oldValues[i] == null && newValues[i] != null)) {//如果数据有变化
		    		if (newValues[i] instanceof PersistentCollection)      continue;	//如果为集合，则忽略	                
		    		if(properties[i].equalsIgnoreCase("version")) continue;//版本变化，忽略		    				    		
		    		if(oldValues[i] instanceof Model) {
		    			oldValues[i] = getEntityId(event.getSession(),oldValues[i]);
		    		}
		    		if(newValues[i] instanceof Model) {
		    			newValues[i] = getEntityId(event.getSession(),newValues[i]);
		    		}
		    		//HistoryElement element = new HistoryElement(String.valueOf(properties[i]),String.valueOf(oldValues[i]),String.valueOf(newValues[i]));
		    		
		    		oldDataMap.put(properties[i], oldValues[i]);
		    		newDataMap.put(properties[i], newValues[i]);
		    		
		    		isChanged = true;
		    		
		    		if(properties[i].equalsIgnoreCase("isdeleted") ){
		    			if(Integer.parseInt(newValues[i].toString()) == 1){
		    				isDeleted = true;
		    			}
		    		}
		    		logger.debug(event.getId()+":"+properties[i]+" >>> "+oldValues[i]+" - "+newValues[i]);
		    	 }
		     }
		     if(isChanged){
		    	  HistoryModel historyModel = new HistoryModel();
		    	  if(isDeleted){
		    		  historyModel.setOperatorType(OperationType.DELETE);
		    	  }else{
		    		  historyModel.setOperatorType(OperationType.UPDATE);
		    		  historyModel.setBeforeValue(JsonUtils.mapToJson(oldDataMap));
					  historyModel.setAfterValue(JsonUtils.mapToJson(newDataMap));
		    	  }
		    	 
				  historyModel.setEntiryId(String.valueOf(event.getId()));
				  historyModel.setEntiryName(event.getEntity().getClass().getSimpleName());				 
				  historyModel.setOperatorMan(currentUser.getCnName());
				  historyModel.setOperatorManId(currentUser.getResourceid());
				  historyModel.setOperatorIp(currentUser.getLoginIp());
				  logHistory(event.getSession(),historyModel);
		     }
		   		
		}
	
	}

	/*
	 * 删除审计	
	 * 物理删除  
	 * @see org.hibernate.event.PostDeleteEventListener#onPostDelete(org.hibernate.event.PostDeleteEvent)
	 */
	public void onPostDelete(PostDeleteEvent event) {
		Object entity = event.getEntity();
		User currentUser = SpringSecurityHelper.getCurrentUser();
		if(isAableLog(entity,OperationType.TRUNCATE)){
			 HistoryModel historyModel = new HistoryModel();
			 historyModel.setOperatorType(OperationType.TRUNCATE);
			 historyModel.setEntiryId(String.valueOf(event.getId()));
			 historyModel.setEntiryName(event.getEntity().getClass().getSimpleName());
			 historyModel.setOperatorMan(currentUser.getCnName());
			 historyModel.setOperatorManId(currentUser.getResourceid());
			 historyModel.setOperatorIp(currentUser.getLoginIp());
			 logHistory(event.getSession(),historyModel);
		}
		
	}

	/*
	 * 插入审计
	 * @see org.hibernate.event.PostInsertEventListener#onPostInsert(org.hibernate.event.PostInsertEvent)
	 */
	public void onPostInsert(PostInsertEvent event) {
		User currentUser = SpringSecurityHelper.getCurrentUser();
		Object entity = event.getEntity();
		if(isAableLog(entity,OperationType.INSERT)){
			 HistoryModel historyModel = new HistoryModel();
			 historyModel.setOperatorType(OperationType.INSERT);
			 historyModel.setEntiryId(String.valueOf(event.getId()));
			 historyModel.setEntiryName(event.getEntity().getClass().getSimpleName());
			 historyModel.setOperatorMan(currentUser.getCnName());
			 historyModel.setOperatorManId(currentUser.getResourceid());
			 historyModel.setOperatorIp(currentUser.getLoginIp());
			 logHistory(event.getSession(),historyModel);			
		}
		
	}
	
	//判断当前实体是否可记录日志
	private boolean isAableLog(Object entity,OperationType oprateType){		 
		 Historizable historizable = entity.getClass().getAnnotation(Historizable.class);
		 if(null != historizable && historizable.logable()){//可记录日志
			 //拿实体的enableLogHistory值
			 try{
				 boolean enableLogHistory = (Boolean)ExBeanUtils.getFieldValue(entity,"enableLogHistory");
				 if(enableLogHistory){
					 for(int i=0;i<historizable.value().length;i++){
						 if(oprateType.equals(historizable.value()[i])){
							 return true;
						 }//end if
					 }//end for
				 }//end if
				 
			 }catch(Exception e){
				 //do nothing
			 }		
			
		 }		
		return false;
	}

	//记录审计日志
	private void logHistory(EventSource session,HistoryModel historyModel){
		Session tempSession = session.getSessionFactory().openSession();
		Transaction tx = tempSession.beginTransaction();
		try {
            tx.begin();
            tempSession.save(historyModel);
            tempSession.flush();
            tx.commit();
            logger.info("log history for model[{}] sucessed...",historyModel.getEntiryName());
        } catch (Exception ex) {
            tx.rollback();            
        }finally{
        	tempSession.close();
        }
       
	}
	
	private Serializable getEntityId(EventSource session,Object obj){		
		LazyInitializer lazy = ((HibernateProxy) obj).getHibernateLazyInitializer();			
		final Object item = lazy.getImplementation();
		return session.getPersistenceContext().getEntry(item).getId();			
		
	}
	

}
